package org.wheel.module.core.config.cookie;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;

import java.time.Duration;


/**
 * 基于Spring-security组件，登陆后，向前端cookie里面写入值
 * 适用 PC 端，移动端自己写token
 * <pre>
 * ### ✅ 总结：自动判断逻辑表
 *
 * 表格
 *
 * 复制
 *
 * | 环境 | 协议  | httpOnly | secure | sameSite |
 * | :--- | :---- | :------- | :----- | :------- |
 * | dev  | HTTP  | false    | false  | Lax      |
 * | dev  | HTTPS | true     | true   | None     |
 * | prod | HTTP  | ❌不推荐  | ❌无效  | ❌不推荐  |
 * | prod | HTTPS | true     | true   | None     |
 *
 * ------
 *
 * ### ✅ 建议
 *
 * - **生产环境务必使用 HTTPS**，否则 `secure=true` 的 Cookie 会被浏览器拒绝。
 * - **开发环境可用 HTTP**，但建议本地也启用 HTTPS（用 mkcert 等工具），更接近生产行为。
 * </pre>
 */
public class CustomCookies {

    private final CookieProperties props;
    private final Environment env;

    public CustomCookies(CookieProperties props, Environment env) {
        this.props = props;
        this.env = env;
    }

    /**
     * 唯一对外 API
     * <pre>
     * 说明：
     *
     * - `ResponseCookie.maxAge(-1)` 会**不输出** `Max-Age` 和 `Expires`，浏览器行为 = **session cookie**
     * - 如果你想让“永不过期”真的写一个大数字，也可改为 `builder.maxAge(Duration.ofDays(3650))`（10 年）
     * </pre>
     */
    public void setCookie(HttpServletResponse response,
                          String name,
                          String value,
                          HttpServletRequest request) {

        boolean prod = env.acceptsProfiles("prod");
        String requestDomain = extractDomain(request);   // 工具方法，见后
        /* ---------- 生产环境校验 ---------- */
        if (prod && !CollUtil.isEmpty(props.getDomain())
                && !props.getDomain().contains(requestDomain)) {
            throw new IllegalStateException(
                    "当前域名 " + requestDomain + " 不在允许列表 " + props.getDomain());
        }

        /* ---------- 组装 Cookie ---------- */
        ResponseCookie.ResponseCookieBuilder builder = ResponseCookie.from(name, value)
                .path("/");

        int cfg = props.getMaxAge();
        if (cfg == -1) {
            // session cookie：Spring 的 ResponseCookie 不支持直接省略 maxAge，
            // 但把 maxAge 写成 -1 时，底层不会输出 Max-Age 和 Expires，效果等同 session
            builder.maxAge(-1);
        } else if (cfg == 0) {
            // 永不过期：同样用 -1，浏览器侧即“永久”
            // 原意：最大过期时长，-1是随session 0-是删除，目前不需要0-删除选项，所以这里改为-1
            builder.maxAge(-1);
        } else {
            builder.maxAge(Duration.ofSeconds(cfg));
        }

        if (prod) {                       // 生产环境
            builder.httpOnly(props.isHttpOnly())
                    .secure(props.isSecure() && request.isSecure()) // 仅 https 时 secure=true
                    .sameSite("None");
        } else {                          // 开发/测试
            builder.httpOnly(false)
                    .secure(false)
                    .sameSite("Lax");
        }

        if (prod && !CollUtil.isEmpty(props.getDomain())) {
            builder.domain(requestDomain);   // 强制与当前域名一致
        }

        response.setHeader(HttpHeaders.SET_COOKIE, builder.build().toString());
    }
    /* 简单提取主域，可按需替换 */
    private String extractDomain(HttpServletRequest request) {
        String server = request.getServerName();
        return server.startsWith("www.") ? server.substring(4) : server;
    }

    /**
     * 得到cookie的域名
     */
    private String getDomainName(HttpServletRequest request) {
        String domainName = null;

        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
            domainName = "";
        } else {
            serverName = serverName.toLowerCase();
            serverName = serverName.substring(7);
            final int end = serverName.indexOf("/");
            serverName = serverName.substring(0, end);
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
                // www.xxx.com.cn
                domainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
                // xxx.com or xxx.cn
                domainName = domains[len - 2] + "." + domains[len - 1];
            } else {
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }
}